﻿// -----------------------------------------------------------------------
// <copyright file="Program.cs" company="G.W. van der Vegt">
// SharpForth is inspired by JonesForthInC v1.48 and bb4wForth.
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;

namespace SharpForth
{
    class Program
    {

        #region Fields

        private static String buffer = String.Empty;
        private static String line = String.Empty;

        #endregion Fields

        /// <summary>
        /// Input on a Line basis and append to Forth.input Queue.
        /// Append an extra \n.
        /// </summary>
        private static void Forth_OnGetKey(Boolean buffer)
        {
            if (Console.KeyAvailable)
            {
                switch (buffer)
                {
                    case true:
                        {
                            String line = Console.ReadLine();

                            if (line.Length != 0)
                            {
                                foreach (Char ch in line)
                                {
                                    Forth.input.Enqueue(ch);
                                }

                                Forth.input.Enqueue('\n');
                            }
                        }
                        break;
                    case false:
                        {
                            do
                            {
                                Char ch = Console.ReadKey(true).KeyChar;

                                if (ch == '\r' || ch == '\n' || (ch >= 32 && ch < 127))
                                {
                                    Console.Write(ch);
                                    if (ch == '\r')
                                    {
                                        Console.Write('\n');
                                    }
                                    Forth.input.Enqueue(ch);
                                    break;
                                }
                                else
                                {
                                    // Bell
                                }
                            } while (true);
                        }
                        break;
                }
            }
            else
            {
                Application.DoEvents();
            }
        }

        private static void Forth_OnOutput(String txt, Boolean line)
        {
            //Debug.Print(txt);

            Console.ForegroundColor = ConsoleColor.White;

            if (txt.StartsWith(Forth.ErrorMarker))
            {
                Console.ForegroundColor = ConsoleColor.Red;
            }
            else if (txt.Equals(Forth.OkMarker))
            {
                Console.ForegroundColor = ConsoleColor.Gray;
            }
            else if (txt.Equals(Forth.CLsMarker))
            {
                Console.Clear();
                txt = String.Empty;
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
            }
            if (txt != "\0")
            {
                Console.Write(txt);
            }
            if (line)
            {
                Console.WriteLine(String.Empty);
            }

            Console.ForegroundColor = ConsoleColor.White;
        }

        public static void StartForth()
        {
            Object t = Type.GetType("Mono.Runtime");
            if (t != null)
            {
                // Mono
            }
            else
            {
                Console.WindowHeight = Forth.TerminalHeight;
                Console.WindowWidth = Forth.TerminalWidth;
            }
            Console.CursorVisible = true;

            //Console.TreatControlCAsInput = true;
            //Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

            Forth.OnKeyAvailableEvent += new Forth.KeyAvailableDelegate(Forth_OnKeyAvailable);
            Forth.OnGetKeyEvent += new Forth.GetKeyDelegate(Forth_OnGetKey);
            Forth.OnOutputEvent += new Forth.OutputDelegate(Forth_OnOutput);
            Forth.OnGotoXYEvent += new Forth.GotoXYDelegate(Forth_OnGotoXYEvent);

            //! Start the Interpreter by executing QUIT (which initializes the Forth Interpreter and subsequently starts calls INTERPRET in a loop).
            Forth.Init();
            Thread.Sleep(1000);
        }

        static void Forth_OnGotoXYEvent(Int32 x, Int32 y)
        {
            Console.CursorLeft = x;
            Console.CursorTop = y;
        }

        static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            Forth.Shutdown = true;
        }

        /// <summary>
        /// Return true if Console Input is available,
        /// </summary>
        /// <returns>true if input is available</returns>
        static bool Forth_OnKeyAvailable()
        {
            return Console.KeyAvailable;
        }

        static void Main(string[] args)
        {
            Console.Title = String.Format("SharpForth v{0}", Forth.SharpForthVersion);

            if (args.Length == 1)
            {

            }

            StartForth();
        }
    }
}
